/*
 * BinaryBlobType.java
 *
 * Created on 21 aprile 2006, 12.10
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package it.azienda.framework.utilita;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;

/**
 *
 * @author SStefanini
 */

public class BinaryBlobType implements UserType {
    public int[] sqlTypes() {
        return new int[] { java.sql.Types.BLOB };
    }

    public Class returnedClass() {
        return byte[].class;
    }

    public boolean equals(Object x, Object y) {
        return (x == y) || (x != null && y != null && java.util.Arrays.equals((byte[]) x, (byte[]) y));
    }

    public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
        if (st instanceof oracle.jdbc.OraclePreparedStatement) {
            oracle.sql.BLOB blob = oracle.sql.BLOB.createTemporary(
                    (oracle.jdbc.driver.OracleConnection)st.getConnection(), false, oracle.sql.BLOB.DURATION_SESSION);
            blob.open(oracle.sql.BLOB.MODE_READWRITE);
            try {
                java.io.OutputStream out = blob.setBinaryStream(0);
                if (value != null) out.write((byte[])value);
                out.flush();
                out.close();
            } catch (IOException e) {
                throw new SQLException("failed write to oracle blob" + e.getMessage());
            }
            blob.close();
            ((oracle.jdbc.OraclePreparedStatement)st).setBLOB(index, blob);

        } else if (st instanceof org.firebirdsql.jdbc.FBPreparedStatement) {
            org.firebirdsql.jdbc.FBBlob blob = new org.firebirdsql.jdbc.FBBlob(
                    (org.firebirdsql.jdbc.AbstractConnection)st.getConnection());
            try {
                java.io.OutputStream out = blob.setBinaryStream(0);
                if (value != null) out.write((byte[])value);
                out.flush();
                out.close();
                blob.close();
            } catch (IOException e) {
                throw new SQLException("failed write to firebird blob" + e.getMessage());
            }
            ((org.firebirdsql.jdbc.FBPreparedStatement)st).setBlob(index, blob);

        } else if (st instanceof com.mchange.v2.c3p0.impl.NewProxyPreparedStatement) {
            boolean isOracle = false;
            boolean isFirebird = false;
            java.sql.DatabaseMetaData dbMetaData = st.getConnection().getMetaData();
            if (dbMetaData.getDriverName().equals("Oracle JDBC driver")) {
                isOracle = true;
            } else if (dbMetaData.getDriverName().equals("JayBird JCA/JDBC driver")) {
                isFirebird = true;
            }
            if (isOracle) {
                com.mchange.v2.c3p0.impl.NewProxyConnection castCon =
                        (com.mchange.v2.c3p0.impl.NewProxyConnection) st.getConnection();
                java.lang.reflect.Method m;
                oracle.sql.BLOB blob;
                try {
                    m = oracle.sql.BLOB.class.getMethod(
                            "createTemporary", new Class[] {java.sql.Connection.class, boolean.class, int.class});
                    Object[] args = new Object[] {com.mchange.v2.c3p0.impl.NewProxyConnection.RAW_CONNECTION,
                            Boolean.valueOf(false), new Integer(oracle.sql.BLOB.DURATION_SESSION)};
                    blob = (oracle.sql.BLOB) castCon.rawConnectionOperation(m, null, args);
                    blob.open(oracle.sql.BLOB.MODE_READWRITE);
                    java.io.OutputStream out = blob.setBinaryStream(0);
                    if (value != null) out.write((byte[])value);
                    out.flush();
                    out.close();
                    blob.close();
                    st.setBlob(index, blob);
                } catch (SecurityException ex) {
                    ex.printStackTrace();
                } catch (NoSuchMethodException ex) {
                    ex.printStackTrace();
                } catch (IllegalArgumentException ex) {
                    ex.printStackTrace();
                } catch (InvocationTargetException ex) {
                    ex.printStackTrace();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                } catch (IllegalAccessException ex) {
                    ex.printStackTrace();
                } catch (IOException e) {
                    throw new SQLException("failed write to oracle blob" + e.getMessage());
                }

            } else if (isFirebird) {
                com.mchange.v2.c3p0.impl.NewProxyConnection castCon =
                        (com.mchange.v2.c3p0.impl.NewProxyConnection) st.getConnection();
                java.lang.reflect.Method m;
                org.firebirdsql.jdbc.FBBlob blob;
                try {
                    m = org.firebirdsql.jdbc.FBConnection.class.getMethod("createBlob", new Class[] {});
                    Object[] args = new Object[] {};
                    blob = (org.firebirdsql.jdbc.FBBlob) castCon.rawConnectionOperation(m, castCon.RAW_CONNECTION, args);
                    java.io.OutputStream out = blob.setBinaryStream(0);
                    if (value != null) out.write((byte[])value);
                    out.flush();
                    out.close();
                    blob.close();
                    st.setBlob(index, blob);
                } catch (SecurityException ex) {
                    ex.printStackTrace();
                } catch (NoSuchMethodException ex) {
                    ex.printStackTrace();
                } catch (IllegalArgumentException ex) {
                    ex.printStackTrace();
                } catch (InvocationTargetException ex) {
                    ex.printStackTrace();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                } catch (IllegalAccessException ex) {
                    ex.printStackTrace();
                } catch (IOException e) {
                    throw new SQLException("failed write to firebird blob" + e.getMessage());
                }
            }

        } else {
            st.setBlob(index, org.hibernate.Hibernate.createBlob((byte[]) value));
        }
    }

    public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
        Object ritorno = null;
        final java.sql.Blob blob = rs.getBlob(names[0]);
        if (blob != null) {
            long grandezza = blob.length();
            ritorno = new byte[(int)grandezza];
            try {
                java.io.InputStream inputStream = blob.getBinaryStream();
                inputStream.read((byte[])ritorno);
            } catch (IOException e) {
                throw new SQLException("failed read blob" + e.getMessage());
            }
        }
        return ritorno;
        //final Blob blob = rs.getBlob(names[0]);
        //return blob != null ? blob.getBytes(1, (int)blob.length()) : null;
    }

    public Object deepCopy(Object value) {
        if (value == null) return null;
        byte[] bytes = (byte[]) value;
        byte[] result = new byte[bytes.length];
        System.arraycopy(bytes, 0, result, 0, bytes.length);
        return result;
    }

    public boolean isMutable() {
        return true;
    }

    public int hashCode(Object x) throws HibernateException {
        return x.hashCode();
    }

    public Serializable disassemble(Object value) throws HibernateException {
        return (Serializable) value;
    }

    public Object assemble(Serializable cached, Object owner) throws HibernateException {
        return cached;
    }

    public Object replace(Object original, Object target, Object owner) throws HibernateException {
        return original;
    }
}
